home *** CD-ROM | disk | FTP | other *** search
/ MacGames Sampler / PHT MacGames Bundle.iso / MacSource Folder / Samples from the CD / Editors / emacs / Emacs-1.14b1-sources / sources / utility-src / sh.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-30  |  12.0 KB  |  505 lines  |  [TEXT/EMAC]

  1. /*
  2.  * Copyright (C) 1993, 1994 Marc Parmet.
  3.  * This file is part of the Macintosh port of GNU Emacs.
  4.  *
  5.  * GNU Emacs is distributed in the hope that it will be useful,
  6.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  7.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  8.  * GNU General Public License for more details.
  9.  */
  10.  
  11. #include <MacHeaders>
  12. #include "sys/dir.h"
  13. #include "stdio.h"
  14. #include "getopt.h"
  15. #include "regex.h"
  16. #include "vfork.h"
  17.  
  18. static char debug = 0;
  19. static char *progname;
  20.  
  21. enum {
  22.     noneFoundErr = 3
  23. };
  24.  
  25. static char upcase[0400] = 
  26.   { 000, 001, 002, 003, 004, 005, 006, 007,
  27.     010, 011, 012, 013, 014, 015, 016, 017,
  28.     020, 021, 022, 023, 024, 025, 026, 027,
  29.     030, 031, 032, 033, 034, 035, 036, 037,
  30.     040, 041, 042, 043, 044, 045, 046, 047,
  31.     050, 051, 052, 053, 054, 055, 056, 057,
  32.     060, 061, 062, 063, 064, 065, 066, 067,
  33.     070, 071, 072, 073, 074, 075, 076, 077,
  34.     0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  35.     0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  36.     0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  37.     0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
  38.     0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  39.     0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  40.     0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  41.     0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
  42.     0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
  43.     0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
  44.     0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
  45.     0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
  46.     0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
  47.     0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
  48.     0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
  49.     0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
  50.     0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
  51.     0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
  52.     0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
  53.     0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
  54.     0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
  55.     0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
  56.     0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
  57.     0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
  58.   };
  59.  
  60. struct re_pattern_buffer searchbuf;
  61.  
  62. static void
  63. init_searchbuf(void)
  64. {
  65. #define BYTEWIDTH 8
  66.     char fastmap[(1 << BYTEWIDTH)];
  67.  
  68.     searchbuf.allocated = 40;
  69.     searchbuf.buffer = NewPtr(searchbuf.allocated);
  70.     searchbuf.fastmap = fastmap;
  71.     searchbuf.translate = upcase;
  72. }
  73.  
  74. static int
  75. get_file_list1(char *dirname,int *nfiles,char ****file_list)
  76. {
  77.     int i,err;
  78.     char *s;
  79.     DIR *dir;
  80.     struct direct *f;
  81.  
  82.     *file_list = 0L;
  83.     *nfiles = 0;
  84.  
  85.     dir = opendir(dirname);
  86.     if (dir == 0L) return memFullErr;
  87.     *file_list = NewHandle(0L);
  88.     while ((f = readdir(dir)) != 0L) {
  89.         SetHandleSize(*file_list,(*nfiles+1) * sizeof(char *));
  90.         err = MemError(); if (err) return err;
  91.         s = NewPtr(strlen(f->d_name) + 1);
  92.         err = MemError(); if (err) return err;
  93.         strcpy(s,f->d_name);
  94.         (**file_list)[*nfiles] = s;
  95.         ++*nfiles;
  96.     }
  97.     closedir(dir);
  98.     return noErr;
  99. }
  100.  
  101. static char
  102. lastchar(char *s)
  103. {
  104.     int len = strlen(s);
  105.     if (len == 0)
  106.         return '\0';
  107.     else
  108.         return s[len-1];
  109. }
  110.  
  111. static int
  112. get_file_list(char *cwd,char *pathname,int *nfiles,char ****file_list)
  113. {
  114.     int err;
  115.     
  116.     if (pathname == 0L) {
  117.         if (cwd == 0L) {
  118.             fprintf(stderr,"%s: Cannot expand file names without "
  119.                     "current working directory.\n",progname);
  120.             return dirNFErr;
  121.         }
  122.         else
  123.             return get_file_list1(cwd,nfiles,file_list);
  124.     }
  125.     else if (pathname[0] == '/' || (pathname[0] == '~' && pathname[1] != '\0')) {
  126.         return get_file_list1(pathname,nfiles,file_list);
  127.     }
  128.     else {
  129.         int cwd_len,pathname_len;
  130.         char *complete_pathname;
  131.  
  132.         if (cwd == 0L) {
  133.             fprintf(stderr,"%s: Cannot expand file names without "
  134.                     "current working directory.\n",progname);
  135.             return 0L;
  136.         }
  137.  
  138.         cwd_len = strlen(cwd);
  139.         pathname_len = strlen(pathname);
  140.         complete_pathname = NewPtr(cwd_len + pathname_len + 2);
  141.         err = MemError(); if (err) return err;
  142.         strcpy(complete_pathname,cwd);
  143.         if (lastchar(cwd) != '/') strcat(complete_pathname,"/");
  144.         strcat(complete_pathname,pathname);
  145.         err = get_file_list1(complete_pathname,nfiles,file_list);
  146.         DisposPtr(complete_pathname);
  147.         return err;
  148.     }
  149. }
  150.  
  151. void
  152. dispose_file_list(char ***file_list,int nfiles)
  153. {
  154.     int i;
  155.     
  156.     for (i = 0; i<nfiles; ++i)
  157.         DisposPtr((*file_list)[i]);
  158.     DisposHandle(file_list);
  159. }
  160.  
  161. static void
  162. convert_to_unix_pattern(char *in,char **out)
  163. {
  164.     int i;
  165.     
  166.     *out = NewPtr(strlen(in)*2+3);
  167.     i = 0;
  168.     (*out)[i++] = '^';
  169.     while (1) {
  170.         if (*in == '\0') {
  171.             (*out)[i++] = '$';
  172.             (*out)[i++] = '\0';
  173.             return;
  174.         }
  175.         else if (*in == '*') {
  176.             (*out)[i++] = '.';
  177.             (*out)[i++] = '*';
  178.         }
  179.         else if (*in == '.') {
  180.             (*out)[i++] = '\\';
  181.             (*out)[i++] = '.';
  182.         }
  183.         else
  184.             (*out)[i++] = *in;
  185.  
  186.         ++in;
  187.     }
  188. }
  189.  
  190. static int
  191. find_matches(char ***file_list,int nfiles,char *s,char ***matches,int *nmatches)
  192. {
  193.     char *t;
  194.     int i,k,len,err;
  195.  
  196.     *nmatches = 0;
  197.     SetHandleSize(matches,0);
  198.  
  199.     convert_to_unix_pattern(s,&t);
  200.     re_compile_pattern(t,strlen(t),&searchbuf);
  201.     DisposPtr(t);
  202.     for (i = 0; i<nfiles; ++i) {
  203.         len = strlen((*file_list)[i]);
  204.         k = re_match(&searchbuf,(*file_list)[i],len,0,0);
  205.         if (k>=0) {
  206.             SetHandleSize(matches,(*nmatches+1) * sizeof(char *));
  207.             err = MemError(); if (err) return err;
  208.             t = NewPtr(strlen((*file_list)[i]) + 1);
  209.             err = MemError(); if (err) return err;
  210.             strcpy(t,(*file_list)[i]);
  211.             (*matches)[*nmatches] = t;
  212.             ++*nmatches;
  213.         }
  214.     }
  215.     
  216.     return noErr;
  217. }
  218.  
  219. static void
  220. separate_pathname_from_filename(char **pathname,char **filename)
  221. {
  222.     int i;
  223.  
  224.     // Need to separate pathname from filename
  225.     i = strlen(*filename)-1;
  226.     *pathname = 0L;
  227.     while (1) {
  228.         if (i < 0) break;
  229.         if ((*filename)[i] == '/') {
  230.             *pathname = NewPtr(i+2);
  231.             memcpy(*pathname,*filename,i+1);
  232.             (*pathname)[i+1] = '\0';
  233.             *filename = *filename+i+1;
  234.             if (debug) printf("pathname is >%s<, filename is >%s<\n",*pathname,*filename);
  235.             break;
  236.         }
  237.         --i;
  238.     }
  239. }
  240.  
  241. static void
  242. do_one_command(char *cmd)
  243. {
  244.     int argstart,nmatches,cwd_err;
  245.     int i,j,len,arglen,new_argc1,new_argc2,nfiles,status;
  246.     char cwd[MAXNAMLEN+1];
  247.     int pid;
  248.     char *p,*t,*pathname,*filename,*newprogname;
  249.     char ***matches,***file_list,***new_argv1,***new_argv2;
  250.     short err;
  251.  
  252.     new_argv1 = new_argv2 = 0;
  253.  
  254.     cwd_err = (getwd(cwd) == 0L);
  255.  
  256.     if (debug) printf("sh: Separating arguments...\n");
  257.  
  258.     // args are the words of argv[k]
  259.     i = new_argc1 = 0;
  260.     len = strlen(cmd);
  261.     new_argv1 = NewHandle(0);
  262.     err = MemError(); if (err) goto error;
  263.     while (1) {
  264.         if (i == len) break;
  265.         while (i<len && cmd[i] == ' ')
  266.             ++i;
  267.         if (i == len) break;
  268.         argstart = i;
  269.         while (i<len && cmd[i] != ' ')
  270.             ++i;
  271.         ++new_argc1;
  272.         arglen = i - argstart;
  273.         SetHandleSize(new_argv1,new_argc1 * sizeof(char *));
  274.         err = MemError(); if (err) goto error;
  275.         t = NewPtr(arglen+1);
  276.         err = MemError(); if (err) goto error;
  277.         (*new_argv1)[new_argc1-1] = t;
  278.         memcpy((*new_argv1)[new_argc1-1],cmd+argstart,arglen);
  279.         (*new_argv1)[new_argc1-1][arglen] = '\0';
  280.     }
  281.     
  282.     if (debug) {
  283.         printf("Before expansion, there are %d arguments:\n",new_argc1);
  284.         for (i = 0; i<new_argc1; ++i)
  285.             printf(">%s<\n",(*new_argv1)[i]);
  286.     }
  287.  
  288.     // Remove a first argument 'exec'
  289.     if (!strcmp((*new_argv1)[0],"exec")) {
  290.         for (i = 0; i<new_argc1-1; ++i)
  291.             (*new_argv1)[i] = (*new_argv1)[i+1];
  292.         --new_argc1;
  293.     }
  294.  
  295.     // Need to remove first argument 'env'
  296.     
  297.     new_argc2 = 0;
  298.     new_argv2 = NewHandle(0L);
  299.     err = MemError(); if (err) goto error;
  300.     
  301.     // Need to expand arguments with wildcards relative to cwd.
  302.     for (i = 0; i<new_argc1; ++i) {
  303.         filename = (*new_argv1)[i];
  304.         separate_pathname_from_filename(&pathname,&filename);
  305.  
  306.         if (has_star(filename)) {
  307.             err = get_file_list(cwd_err ? 0L : cwd,pathname,&nfiles,&file_list);
  308.             if (err) continue;
  309.  
  310.             matches = NewHandle(0L);
  311.             if (MemError()) goto error;
  312.             err = find_matches(file_list,nfiles,filename,matches,&nmatches);
  313.             if (err) goto error;
  314.             if (nmatches == 0) { err = noneFoundErr; goto error; }
  315.  
  316.             SetHandleSize(new_argv2,(new_argc2 + nmatches) * sizeof(char *));
  317.             err = MemError(); if (err) goto error;
  318.             for (j = 0; j<nmatches; ++j) {
  319.                 if (pathname == 0L)
  320.                     (*new_argv2)[new_argc2 + j] = (*matches)[j];
  321.                 else {
  322.                     int match_len = strlen((*matches)[j]);
  323.                     int pathname_len = strlen(pathname);
  324.                     char *complete_match = NewPtr(match_len + pathname_len + 2);
  325.                     strcpy(complete_match,pathname);
  326.                     if (lastchar(pathname) != '/') strcat(complete_match,"/");
  327.                     strcat(complete_match,(*matches)[j]);
  328.                     (*new_argv2)[new_argc2 + j] = complete_match;
  329.                 }
  330.             }
  331.             new_argc2 += nmatches;
  332.  
  333.             DisposHandle(matches);
  334.  
  335.             dispose_file_list(file_list,nfiles);
  336.         }
  337.         else {
  338.             SetHandleSize(new_argv2,(new_argc2 + 1) * sizeof(char *));
  339.             err = MemError(); if (err) goto error;
  340.             (*new_argv2)[new_argc2] = (*new_argv1)[i];
  341.             ++new_argc2;
  342.         }
  343.  
  344.         if (pathname != 0L) DisposPtr(pathname);
  345.     }
  346.     
  347.     if (debug) {
  348.         printf("After expansion, there are %d arguments:\n",new_argc2);
  349.         for (i = 0; i<new_argc2; ++i)
  350.             printf(">%s<\n",(*new_argv2)[i]);
  351.     }
  352.  
  353.     // Add final null pointer to argument list    
  354.     SetHandleSize(new_argv2,(new_argc2 + 1) * sizeof(char *));
  355.     err = MemError(); if (err) goto error;
  356.     (*new_argv2)[new_argc2] = 0L;
  357.  
  358.     HLock(new_argv2);
  359.     newprogname = (*new_argv2)[0];
  360.     if (!strcmp(newprogname,"pwd")) {
  361.         if (cwd_err)
  362.             printf("No current directory is set.\n");
  363.         else
  364.             printf("%s\n",cwd);
  365.     }
  366.     else if (!strcmp(newprogname,"cd")) {
  367.         if (new_argc2 == 1)
  368.             chdir("~/");
  369.         else if ((*new_argv2)[1][0] == '/' ||
  370.                 ((*new_argv2)[1][0] == '~' && (*new_argv2)[1][1] != '\0'))
  371.             chdir((*new_argv2)[1]);
  372.         else {
  373.             Handle s;
  374.             FSSpec spec;
  375.             char *p;
  376.  
  377.             // We need to check that the result is indeed a directory.
  378.  
  379.             if (cwd_err) { err = memFullErr; goto error; }
  380.             p = NewPtr(strlen(cwd) + strlen((*new_argv2)[1]) + 2);
  381.             err = MemError(); if (err) goto error;
  382.             strcpy(p,cwd);
  383.             if (p[strlen(p)-1] != '/') strcat(p,"/");
  384.             strcat(p,(*new_argv2)[1]);
  385.             err = chdir(p);
  386.             DisposPtr(p);
  387.         }
  388.  
  389.         cwd_err = (getwd(cwd) == 0L);
  390.         if (cwd_err) fprintf(stderr,"Couldn't change directory\n");
  391.     }
  392.     else if (!strcmp(newprogname,"exit"))
  393.         exit(0);
  394.     else if (!strcmp(newprogname,"debug"))
  395.         debug = !debug;
  396.     else {
  397.         if (newprogname[0] != '/') {
  398.             // Our kludge for an absence of a PATH environment variable
  399.             char *p = NewPtr(strlen(newprogname) + 6);
  400.             strcpy(p,"/bin/");
  401.             strcat(p,newprogname);
  402.             (*new_argv2)[0] = p;
  403.         }
  404.  
  405.         // Must flush.  What about stdin?  The buffer contents just get lost.
  406.         fflush(stdout);
  407.         fflush(stderr);
  408.         
  409.         pid = vfork();
  410.  
  411.         if (pid == -1) {
  412.             fprintf(stderr,"%s: Can't start process '%s'\n",progname,newprogname);
  413.             return;
  414.         }
  415.  
  416.         if (pid == 0) {
  417.             execvp((*new_argv2)[0],*new_argv2);
  418.             fprintf(stderr,"%s: Can't start process '%s'\n",progname,newprogname);
  419.             _exit(1);
  420.         }
  421.  
  422.         if (debug) DebugStr68k("\p%%% Returned from vfork, calling wait");        
  423.         wait(&status);
  424.         if (debug) DebugStr68k("\p%%% Returned from wait");
  425.     }
  426.  
  427.     error:
  428.     if (err == noneFoundErr) fprintf(stderr,"%s: None found\n",progname);
  429.     if (err == memFullErr) fprintf(stderr,"%s: Out of memory\n",progname);
  430.     if (err == dirNFErr) fprintf(stderr,"%s: Directory not found\n",progname);
  431.     if (err == fnfErr) fprintf(stderr,"%s: File not found\n",progname);
  432.     if (new_argv1) DisposHandle(new_argv1);
  433.     if (new_argv2) DisposHandle(new_argv2);
  434. }
  435.  
  436. int
  437. main(int argc,char **argv)
  438. {
  439.     int k,len,c;
  440.     char *p,s[256];
  441.     char interactive,command_in_line;
  442. //    char *argv1[4];
  443.     
  444.     progname = argv[0];
  445.  
  446. #if 0    
  447.     argv1[0] = "sh";
  448.     argv1[1] = "-c";
  449.     argv1[2] = "ls /Rockhopper";
  450.     argv1[2] = "pwd";
  451.     argv1[3] = 0L;
  452.  
  453.     argc = 3;
  454.     argv = argv1;
  455.     init_unix_io_driver(1);
  456. #endif
  457.  
  458.     interactive = command_in_line = 0;
  459.  
  460.     while (1) {
  461.         c = getopt(argc,argv,"ci");
  462.         if (c == EOF) break;
  463.         switch (c) {
  464.         case 'c': command_in_line = 1;    break;
  465.         case 'i': interactive = 1;        break;
  466.         }
  467.     }
  468.     
  469.     k = optind;
  470.  
  471.     if (command_in_line) {
  472.         do_one_command(argv[k]);
  473.         return 0;
  474.     }
  475.     else {
  476.         while (1) {
  477.             printf("$ ");
  478.             fflush(stdout);
  479.             p = fgets(s,sizeof s,stdin);
  480.             if (p == 0L || feof(stdin)) {
  481.                 printf("^D\n");
  482.                 fflush(stdout);
  483.                 return 0;
  484.             }
  485.             len = strlen(s);
  486.             if (len>=1) s[len-1] = '\0';
  487.             if (s[0] != '\0') {
  488.                 if (debug) printf("Got command: >%s<\n",s);
  489.                 do_one_command(s);
  490.             }
  491.         }
  492.         return 0;
  493.     }
  494. }
  495.  
  496. static int
  497. has_star(char *s)
  498. {
  499.     while (1) {
  500.         if (*s == '\0') return 0;
  501.         if (*s == '*') return 1;
  502.         ++s;
  503.     }
  504. }
  505.